package com.hoki.zj.hrm.service.impl;

import com.baomidou.mybatisplus.plugins.Page;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.hoki.zj.hrm.asserts.GlobalAssert;
import com.hoki.zj.hrm.client.AuthServiceClient;
import com.hoki.zj.hrm.domain.Employee;
import com.hoki.zj.hrm.domain.LoginUser;
import com.hoki.zj.hrm.domain.Tenant;
import com.hoki.zj.hrm.dto.EnteringDto;
import com.hoki.zj.hrm.mapper.TenantMapper;
import com.hoki.zj.hrm.query.TenantQuery;
import com.hoki.zj.hrm.service.IEmployeeService;
import com.hoki.zj.hrm.service.ITenantService;
import com.hoki.zj.hrm.utils.AjaxResult;
import com.hoki.zj.hrm.utils.PageList;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author shukei
 * @since 2021-09-11
 */
@Service
public class TenantServiceImpl extends ServiceImpl<TenantMapper, Tenant> implements ITenantService {



    @Autowired
    private TenantMapper tenantMapper;

    @Autowired
    private AuthServiceClient authServiceClient;

    @Autowired
    private IEmployeeService employeeService;

    @Override
    public PageList<Tenant> selectPagelist(TenantQuery query) {
        // 查询总数
        Page<Tenant> page = new Page<>(query.getPage(),query.getRows());
        // 查询数据(关联查询)
        List<Tenant> datas = tenantMapper.selectPageList(page, query);
        return new PageList<>(page.getTotal(), datas);
    }

    /**
     * 2.入驻
     * @param dto
     */
    @Override
    @Transactional // TODO 单体事务对于微服务没用,需要分布式事务
    public void entring(EnteringDto dto) {
        Employee admin = dto.getEmployee();
        admin.setType(Employee.TENANT_ADMIN_STAFF_OR_OTHERS); // 设置类型为机构管理员
        Tenant tenant = dto.getTenant();
        Long mealId = dto.getMealId();
        // 1.参数校验 非空/是否可以重复(业务校验)
        /*if (StringUtils.isEmpty(dto.getTenant().getCompanyName())) {
            throw new GlobalException("请输入公司名");
        }*/

//        Assert.hasText(dto.getTenant().getCompanyName(), "请填写公司名"); // 原生AssertUtils
//        GlobalAssert.hasText(dto.getTenant().getCompanyName(), "请填写公司名!"); // 自定义判断非空
//        GlobalAssert.isValidPhoneNumber(dto.getEmployee().getTel(), "请输入正确的手机号!"); // 自定义判断手机号
//        GlobalAssert.isValidEmail(dto.getEmployee().getEmail(), "请输入正确的邮箱!"); // 判断邮箱

        // 2.远程调用授权中心,生成管理员对应的用户登录信息
        LoginUser loginUser = new LoginUser();
        loginUser.setUsername(admin.getUsername()); // 设置用户名
        String encodedPwd = setPasswordByBCrypt(admin);
        loginUser.setPassword(encodedPwd); // 设置密码,编码后的
        loginUser.setType(LoginUser.LOGIN_TYPE_ADMIN); // 设置类型:后台
        // 调用方法保存后 获取loginId
        AjaxResult result = authServiceClient.addOrUpdate(loginUser);
        if (!result.isSuccess()) throw new RuntimeException("入驻异常"); // 用户登录信息是否保存成功
        Long loginId = Long.valueOf(result.getResultObj().toString());

        // 3.生成租户(机构)对应的管理员()
        setAdmin(admin, encodedPwd, loginId);
        // 3.1设置管理员相关
        employeeService.insert(admin);

        // 4.生成租户信息
        tenant.setRegisterTime(new Date()); // 设置注册时间
        tenant.setState(Tenant.AUDIT_STATE_PENDING); // 设置状态待审核
        tenant.setAdminId(admin.getId());
        super.insert(tenant); // 保存
        // 5.生成租户对应的套餐信息
        Long tenantId = tenant.getId();
        tenantMapper.insertTenantMeal(tenantId, mealId);
        // 6.再次更改loginUser
        loginUser.setTenantId(tenantId); // 设置tenantId
        loginUser.setCompanyName(tenant.getCompanyName()); // 设置companyName
        AjaxResult updateResult = authServiceClient.addOrUpdate(loginUser);
        GlobalAssert.isSuccess(updateResult.isSuccess(), "入驻异常");
    }

    // 设置管理员相关
    private void setAdmin(Employee admin, String encodedPwd, Long loginId) {
        admin.setInputTime(new Date()); // 设置创建时间
        admin.setLoginId(loginId); // 设置loginId
        admin.setPassword(encodedPwd); // 设置密码,编码后的
    }

    // 2.1指定密码编码器BCryptPasswordEncoder
    private String setPasswordByBCrypt(Employee admin) {
        BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
        return passwordEncoder.encode(admin.getPassword());
    }
}
